#include "includes.h"

IPC_		IPC;

struct shmTime {
	int     mode;
	int     count;
	time_t  clockTimeStampSec;
	int     clockTimeStampUSec;
	time_t  receiveTimeStampSec;
	int     receiveTimeStampUSec;
	int     leap;
	int     precision;
	int     nsamples;
	int     valid;
	int     dummy[10];
};


int NTPDstart = 1;


//hmlee - timestamping in application, so accuracy is bad
void ntp_time_get(void)
{
	gettimeofday(&IPC.tv_sys, NULL);
}


//hmlee - need to work around roll-over 2038
time_t ntp_time_convert(struct tm *timeptr)
{
int bits,direction,secs;
struct tm search;
time_t timep;

	/* calculate the number of magnitude bits in a time_t */
	for (bits=0,timep=1;timep>0;bits++,timep<<=1)
		;

	/* if time_t is signed, 0 is the median value else 1<<bits is median */
	timep = (timep<0) ? 0 : ((time_t) 1<<bits);

	/* save the seconds, and take them out of the search */
	secs = timeptr->tm_sec;
	timeptr->tm_sec = 0;

	/* binary search of the time space using the system gmtime() function */
	for (;;) {
	        search = *gmtime(&timep);

		/* compare the two times down to the same day */
		if (((direction = (search.tm_year-timeptr->tm_year))==0) &&
		    ((direction = (search.tm_mon-timeptr->tm_mon))==0))
			direction = (search.tm_mday-timeptr->tm_mday);

		/* compare the rest of the way if necesary */
		if (direction==0) {
			if (((direction = (search.tm_hour-timeptr->tm_hour))==0) &&
			    ((direction = (search.tm_min-timeptr->tm_min))==0))
				direction = search.tm_sec-timeptr->tm_sec;
		}

		/* is the search complete? */
		if (direction==0) {
			timeptr->tm_sec	= secs;
			return timep+secs;
		} else {
			if (bits--<0)
				return -1;
			if (bits<0)
				timep--;
			else if (direction>0)
				timep -= (time_t) 1 << bits;
			else
				timep += (time_t) 1 << bits;
		}
	}

	return -1;
}


void ntp_time_send(void)
{
struct tm tm_time;
struct timeval tv_int;

	if(STATUS_Warmup==OFF && 
		(SYSTEM.OPERATION.STATUS == STATUS_ACTIVE || SYSTEM.OPERATION.STATUS == STATUS_STANDBY))
	{
		tm_time.tm_year = SYSTEM.TIME.UTC.YEAR-1900;
		tm_time.tm_mon = SYSTEM.TIME.UTC.MONTH-1;
		tm_time.tm_mday = SYSTEM.TIME.UTC.DAY;
		tm_time.tm_hour = SYSTEM.TIME.UTC.HOUR;
		tm_time.tm_min = SYSTEM.TIME.UTC.MINUTE;
		tm_time.tm_sec = SYSTEM.TIME.UTC.SECOND;
		tm_time.tm_isdst = 0;
		
		IPC.tv_ext.tv_sec = ntp_time_convert(&tm_time);
		IPC.tv_ext.tv_usec = 0;
	
		switch(SYSTEM.TIME.LEAPSECPENDING){
			case UNDEFINED:
				IPC.leapending = NTP_LEAP_NOTINSYNC;
				break;
			case NO:
				IPC.leapending = NTP_LEAP_NOWARNING;
				break;
			case PLUS:
				IPC.leapending = NTP_LEAP_ADDSECOND;
				break;
			case MINUS:
				IPC.leapending = NTP_LEAP_DELSECOND;
				break;
			case NOW:
				//IPC.q2t.leap_pending = NTP_LEAP_DELSECOND;
				break;
		}
		
		ntp_shm_set();
				
		//kang-------------------------------------------
		if(NTPDstart == 1){
			tv_int.tv_sec = IPC.tv_ext.tv_sec;
			tv_int.tv_usec = IPC.tv_ext.tv_usec;
			
			settimeofday(&tv_int,NULL);
			
			NTPDstart = 0;
			//LogItString6("NTPD Start", 
			//	SYSTEM.TIME.UTC.YEAR, SYSTEM.TIME.UTC.MONTH, SYSTEM.TIME.UTC.DAY, 
			//	SYSTEM.TIME.UTC.HOUR, SYSTEM.TIME.UTC.MINUTE, SYSTEM.TIME.UTC.SECOND);
		}
		//-----------------------------------------------			
		
	}

}


void ntp_shm_open(void)
{
int shmid;

	shmid = shmget(SHMKEY, sizeof(struct shmTime), IPC_CREAT | 0666);
	if(shmid==-1){
		//syslog(LOG_INFO, "shmget %s errno (%d, %s)", 
		//	"ntpd", errno, strerror(errno));
		printf("shmget errno (%d,%s)\n", errno, strerror(errno));
		return;
	}

	IPC.shmt = (struct shmTime *)shmat(shmid, 0, 0);
	if ((int)(long)IPC.shmt==-1) {
		//syslog(LOG_INFO, "shmat %s errno (%d, %s)", 
		//	"ntpd", errno, strerror(errno));
		printf("shmat errno (%d,%s)\n", errno, strerror(errno));
		IPC.shmt=0;
	}
	
	return;
}


void ntp_shm_set(void)
{
	IPC.shmt->mode=1;
	
	IPC.shmt->valid=0; /* this is perhaps overly paranoid */

	__asm__ __volatile__("": : :"memory");
		
	IPC.shmt->precision=(PRECISION*32)/32;
	IPC.shmt->clockTimeStampSec=IPC.tv_ext.tv_sec;
	IPC.shmt->clockTimeStampUSec=0;
	IPC.shmt->receiveTimeStampSec=IPC.tv_sys.tv_sec;
	IPC.shmt->receiveTimeStampUSec=IPC.tv_sys.tv_usec;
	IPC.shmt->leap=IPC.leapending;
	__asm__ __volatile__("": : :"memory");
	
	IPC.shmt->count++;
	IPC.shmt->valid=1;
}




